'use strict'; const { CompoundCommandBuilder, DocumentCommand, AddChildNodesCommandBuilder, NodeChildType } = require('/commands.js'); const { Dialog, DialogResult } = require('/dialog.js'); const { Document } = require('/document.js'); const { Selection, TextSelection } = require('/selections.js'); const { UnitType } = require('/units.js'); const { StoryBuilder } = require('/storybuilder.js'); const { TextFrameNodeDefinition } = require('/nodes.js'); const { RGBA8 } = require('/colours.js'); const { FillDescriptor } = require('/fills.js'); const { StoryDelta, GlyphAttDoubleType } = require('/storydelta.js'); const { StoryRange } = require('/story.js'); const { Font, FontFamily } = require('/fonts.js'); function isOk(result) { return (result?.value ?? result) == DialogResult.Ok.value; } const DIGITS = '0123456789'; const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const LOWER = 'abcdefghijklmnopqrstuvwxyz'; const SYMBOLS = '!@#$%^&*'; function buildCharPool(useDigits, useUpper, useLower, useSymbols) { let pool = ''; if (useDigits) pool += DIGITS; if (useUpper) pool += UPPER; if (useLower) pool += LOWER; if (useSymbols) pool += SYMBOLS; return pool || DIGITS; } function generateRandomText(count, minLen, maxLen, separator, charPool) { const parts = []; for (let i = 0; i < count; i++) { const len = minLen + Math.floor(Math.random() * (maxLen - minLen + 1)); let token = ''; for (let d = 0; d < len; d++) { token += charPool[Math.floor(Math.random() * charPool.length)]; } parts.push(token); } return parts.join(separator); } function randomColour() { const h = Math.random() * 360; const s = 0.7 + Math.random() * 0.3; const v = 0.7 + Math.random() * 0.3; const c = v * s, x = c * (1 - Math.abs((h / 60) % 2 - 1)), m = v - c; let r = 0, g = 0, b = 0; if (h < 60) { r = c; g = x; b = 0; } else if (h < 120) { r = x; g = c; b = 0; } else if (h < 180) { r = 0; g = c; b = x; } else if (h < 240) { r = 0; g = x; b = c; } else if (h < 300) { r = x; g = 0; b = c; } else { r = c; g = 0; b = x; } return RGBA8(Math.round((r+m)*255), Math.round((g+m)*255), Math.round((b+m)*255)); } function applyRandomStyles(doc, node, text, dpi, allFonts, doColour, doSize, doFont, minPt, maxPt) { const compound = CompoundCommandBuilder.create(); const pxPerPt = dpi / 72; for (let i = 0; i < text.length; i++) { const range = new StoryRange(i, i + 1); const deltas = []; if (doColour) { const fill = FillDescriptor.createSolid(randomColour()); deltas.push(StoryDelta.createBrushFill(fill)); } if (doSize) { const pt = minPt + Math.random() * (maxPt - minPt); deltas.push(StoryDelta.createGlyphDouble(GlyphAttDoubleType.Height.value, pt * pxPerPt)); } if (doFont && allFonts.length > 0) { const font = allFonts[Math.floor(Math.random() * allFonts.length)]; deltas.push(StoryDelta.createPostscriptName(font.postscriptName)); } if (deltas.length > 0) { const compositeDelta = deltas.length === 1 ? deltas[0] : StoryDelta.createComposite(deltas); const sel = Selection.create(doc, node); sel.addSubSelectionForNode(node, TextSelection.create(range)); compound.addCommand(DocumentCommand.createFormatText(sel, compositeDelta)); } } doc.executeCommand(compound.createCommand()); } function buildDialog() { const dlg = Dialog.create("Random Text Generator"); const col = dlg.addColumn(); const c1 = col.addGroup("Random settings"); // const countGroup = col.addGroup("Count"); const countCtrl = c1.addUnitValueEditor("Count", UnitType.Number, UnitType.Number, 20, 1, 10000).setPrecision(0); // const minGroup = col.addGroup("Min Length"); const minLenCtrl = c1.addUnitValueEditor("Min Length", UnitType.Number, UnitType.Number, 5, 1, 50).setPrecision(0); // const maxGroup = col.addGroup("Max Length"); const maxLenCtrl = c1.addUnitValueEditor("Max Length", UnitType.Number, UnitType.Number, 10, 1, 50).setPrecision(0); // const sepGroup = col.addGroup("Separator"); const separatorCtrl = c1.addTextBox("Separator", " "); // const cbDigitsGroup = col.addGroup("Include Digits"); const cbDigits = c1.addCheckBox("Include Digits", true); // const cbUpperGroup = col.addGroup("Include Uppercase"); const cbUpper = c1.addCheckBox("Include Uppercase", false); // const cbLowerGroup = col.addGroup("Include Lowercase"); const cbLower = c1.addCheckBox("Include Lowercase", false); // const cbSymbolsGroup = col.addGroup("Include Symbols"); const cbSymbols = c1.addCheckBox("Include Symbols", false); // const cbColourGroup = col.addGroup("Randomise Colours"); const cbColour = c1.addCheckBox("Randomise Colours", true); // const minSizeGroup = col.addGroup("Min Font Size (pt)"); const minSizeCtrl = c1.addUnitValueEditor("Min Font Size (pt)", UnitType.Number, UnitType.Number, 2, 1, 200).setPrecision(0); // const maxSizeGroup = col.addGroup("Max Font Size (pt)"); const maxSizeCtrl = c1.addUnitValueEditor("Max Font Size (pt)", UnitType.Number, UnitType.Number, 50, 1, 200).setPrecision(0); // const cbSizeGroup = col.addGroup("Randomise Font Sizes"); const cbSize = c1.addCheckBox("Randomise Font Sizes", true); // const cbFontGroup = col.addGroup("Randomise Fonts"); const cbFont = c1.addCheckBox("Randomise Fonts", true); dlg.initialWidth = 400; return { dlg, countCtrl, minLenCtrl, maxLenCtrl, separatorCtrl, cbDigits, cbUpper, cbLower, cbSymbols, cbColour, minSizeCtrl, maxSizeCtrl, cbSize, cbFont }; } // ---- MAIN ---- const doc = Document.current; if (!doc) { console.log("ERROR: No document is open."); } else { const selectedNodes = doc.selection.nodes.filter(n => n.isTextNode && !n.isTableTextNode).toArray(); const { dlg, countCtrl, minLenCtrl, maxLenCtrl, separatorCtrl, cbDigits, cbUpper, cbLower, cbSymbols, cbColour, minSizeCtrl, maxSizeCtrl, cbSize, cbFont } = buildDialog(); const result = dlg.runModal(); if (isOk(result)) { const count = Math.round(countCtrl.value); const minLen = Math.round(minLenCtrl.value); const maxLen = Math.max(Math.round(maxLenCtrl.value), minLen); const separator = separatorCtrl.text; const doColour = cbColour.value; const doSize = cbSize.value; const doFont = cbFont.value; const minPt = Math.round(minSizeCtrl.value); const maxPt = Math.max(Math.round(maxSizeCtrl.value), minPt); const charPool = buildCharPool(cbDigits.value, cbUpper.value, cbLower.value, cbSymbols.value); const generatedText = generateRandomText(count, minLen, maxLen, separator, charPool); // Pre-load all fonts once before the per-character loop let allFonts = []; if (doFont) { FontFamily.all.forEach(family => { for (let i = 0; i < family.fontCount; i++) { const f = family.getFont(i); if (f.isValid) allFonts.push(f); } }); } const spread = doc.currentSpread; doc.executeCommand(DocumentCommand.createSetCurrentSpread(spread)); let targetNodes = []; if (selectedNodes.length > 0) { const compound = CompoundCommandBuilder.create(); for (const node of selectedNodes) { const sel = Selection.create(doc, node); sel.addSubSelectionForNode(node, TextSelection.create(node.storyRange)); compound.addCommand(DocumentCommand.createSetText(sel, generatedText)); } doc.executeCommand(compound.createCommand()); targetNodes = selectedNodes; } else { const extents = spread.getSpreadExtents(); const rect = { x: extents.x + 50, y: extents.y + 50, width: extents.width - 100, height: extents.height - 100 }; const sb = StoryBuilder.create(); sb.setToFrameTextDefaultStyle(96, 0); sb.addText(generatedText); const def = TextFrameNodeDefinition.create(sb, rect); const builder = AddChildNodesCommandBuilder.create(); builder.setInsertionTarget(spread); builder.addNode(def); doc.executeCommand(builder.createCommand(true, NodeChildType.Main)); targetNodes = doc.selection.nodes.filter(n => n.isTextNode).toArray(); } if ((doColour || doSize || doFont) && targetNodes.length > 0) { doc.executeCommand(DocumentCommand.createSetCurrentSpread(spread)); for (const node of targetNodes) { applyRandomStyles(doc, node, generatedText, doc.dpi, allFonts, doColour, doSize, doFont, minPt, maxPt); } } } }